from PyQt5.QtCore import QPoint
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QColor
import sys
from numpy import linalg, mat, array

class LeastSquare(QWidget):
    def __init__(self):
        super().__init__()
        self.keys = []
        self.funs = []
        self.coff = []
        self.funs.append(lambda x:1)
        self.funs.append(lambda x:x)
        self.ret = None
    def mousePressEvent(self, e):
        self.keys.append(QPoint(e.x(),e.y()))
        G = [[sum(map(lambda key:rfun(key.x())*cfun(key.x()), self.keys)) for cfun in self.funs] for rfun in self.funs]
        d = [sum(map(lambda key:fun(key.x())*key.y(), self.keys)) for fun in self.funs]
        try:
            self.coff = linalg.solve(G,array(d)).tolist()
        except Exception as e:
            print("Exception in linalg.solve", e)
            return
        def ret(x):
            sum = 0
            for i in range(len(self.funs)):
                sum += self.coff[i]*self.funs[i](x)
            return sum
        self.ret = ret
        self.update()
    def paintEvent(self, e):
        painter = QPainter(self)
        # draw all key points
        painter.setBrush(QColor(255,0,0))
        for key in self.keys:
            painter.drawEllipse(key,2,2)
        # draw approximation function
        if self.ret:
            painter.setBrush(QColor(0,0,0))
            points = [QPoint(x,self.ret(x)) for x in range(0, self.width(), 10)]
            painter.drawPolyline(*points)

app = QApplication(sys.argv)
widget = LeastSquare()
widget.show()
sys.exit(app.exec_())